<template>
  <div id="app">
    <!-- region 按钮组 -->
    <div style="display: flex; flex-direction: row; padding: 10px; justify-content: flex-start; width: 100%;">
      <el-button
        v-if="puzzleItems.length > 0"
        size="mini" round plain type="primary"
        @click="selecting = !selecting; current = null; selectedItems.length = 0;"
      >
        {{ selecting ? '取消选择': '选择' }}
      </el-button>
      <template v-if="!selecting">
        <el-button size="mini" round plain @click="refresh">刷新</el-button>
        <el-button size="mini" round plain @click="newPuzzle">新建关卡</el-button>
        <el-button size="mini" round plain @click="queryVisible = true">创意工坊查询</el-button>
        <el-button size="mini" round plain @click="execCommand('screenshot')">打开截图文件夹</el-button>
      </template>
      <el-button size="mini" round plain v-if="selecting" type="warning"
       @click="selectedItems.length = 0; selectedItems.push(...puzzleItems)">
        全选
      </el-button>
      <el-button size="mini" round plain v-if="selecting" type="warning"
       @click="selectedItems.length = 0; selectedItems.pop();">
        全不选
      </el-button>

      <template v-if="selecting && selectedItems.length">
        <el-button size="mini" round plain @click="operateBatch('subscribe')">订阅</el-button>
        <el-button size="mini" round plain @click="operateBatch('unsubscribe')">取消订阅</el-button>
        <el-button size="mini" round plain @click="operateBatch('favorite')">收藏</el-button>
        <el-button size="mini" round plain @click="operateBatch('unfavorite')">取消收藏</el-button>
        <el-button size="mini" round plain @click="operateBatch('voteUp')">好评</el-button>
        <el-button size="mini" round plain @click="operateBatch('voteDown')">差评</el-button>
        <el-button size="mini" round plain @click="operateBatch('markAsPlayed')">标记为已玩过</el-button>
        <el-button size="mini" round plain @click="copyItemUrls(...selectedItems.map(item => item.fileId))">复制链接</el-button>
      </template>
    </div>
    <!-- endregion -->

    <!-- region 关卡列表 -->
    <div style="
      display: flex;
      flex-direction: row;
      flex-wrap: wrap;
      height: 100%;
      align-content: flex-start;
      overflow: auto;" v-if="puzzleItems.length > 0">
      <div v-for="(item, index) in puzzleItemsPage" :key="index" style="width: 200px; padding: 5px;" @click="clickItem(item)">
        <el-card shadow="hover" style="height: 180px; cursor: pointer;" :style="selectedItems.includes(item) && {borderColor: 'blue'}">
          <el-image :src="getAbsoluteUrl(item.preview)" style="width: 100%; height: 100px;" fit="contain"/>
          <div style="font-size: 13px;">
            {{ item.title }}
          </div>
        </el-card>
      </div>
    </div>

    <el-pagination
      background
      hide-on-single-page
      layout="total, sizes, prev, pager, next, jumper"
      :total="puzzleItems.length"
      :current-page.sync="currentPage"
      :page-size.sync="pageSize"
      style="margin: 5px;"
    />

    <el-card v-if="puzzleItems !== initPuzzleItems && puzzleItems.length === 0" style="height: 100%; margin: 5px; position: relative;">
      <img src="@/assets/img/200.gif" style="
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        object-fit: cover;
      "/>
      <div style="
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        color: deepskyblue;
        display: flex;
        letter-spacing: 5px;
        flex-direction: column;
        justify-content: center;
      "><h1>没查到数据哦～</h1></div>
    </el-card>
    <!-- endregion -->

    <toast/>

    <!-- region 关卡信息弹窗 -->
    <el-drawer :visible.sync="visible" size="570px">
      <div v-if="current" style="padding: 10px; display: flex; flex-direction: column; height: 100%;">
        <el-image
          style="width: 100%; height: 188px;"
          fit="contain"
          :src="getAbsoluteUrl(current.preview)"
          :preview-src-list="[getAbsoluteUrl(current.preview)]"
        />
        <div style="flex: 1; overflow: auto; padding: 10px 0;">
          <el-descriptions direction="vertical" :column="3" border>
            <div slot="title">
              {{ current.title }}
            </div>
            <el-descriptions-item label="操作" :span="3">
              <div style="display: flex; gap: 10px; flex-wrap: wrap;">
                <el-button size="mini" style="margin: 0;" round plain @click="operateBatch('subscribe')">订阅</el-button>
                <el-button size="mini" style="margin: 0;" round plain @click="operateBatch('unsubscribe')">取消订阅</el-button>
                <el-button size="mini" style="margin: 0;" round plain @click="operateBatch('favorite')">收藏</el-button>
                <el-button size="mini" style="margin: 0;" round plain @click="operateBatch('unfavorite')">取消收藏</el-button>
                <el-button size="mini" style="margin: 0;" round plain @click="operateBatch('voteUp')">好评</el-button>
                <el-button size="mini" style="margin: 0;" round plain @click="operateBatch('voteDown')">差评</el-button>
                <el-button size="mini" style="margin: 0;" round plain @click="operateBatch('markAsPlayed')">标记为已玩过</el-button>
                <el-button size="mini" style="margin: 0;" @click="copyItemUrls(current.fileId)" round plain>复制链接</el-button>
                <el-button v-if="gameInfo.workshopType === 0" size="mini" style="margin: 0;" @click="showClone" round plain>克隆关卡</el-button>
              </div>
            </el-descriptions-item>
            <el-descriptions-item label="文件ID" :span="3">
              <span style="margin-right: 10px;">{{ current.fileId }}</span>
              <el-button size="mini" round plain type="primary" @click="showInWorkshop(current.fileId)">
                在创意工坊中查看
              </el-button>
              <el-button v-if="gameInfo.workshopType === 1" size="mini" round plain type="primary" @click="showInLocalDirectory(current.fileId)">
                在本地文件夹中查看
              </el-button>
            </el-descriptions-item>
            <el-descriptions-item label="标题" :span="3">{{ current.title }}</el-descriptions-item>
            <el-descriptions-item label="描述" :span="3">
              <pre style="margin: 0; white-space: pre-wrap; word-wrap: break-word;">{{ current.description }}</pre>
            </el-descriptions-item>
            <el-descriptions-item label="创建时间">{{ current.createTime }}</el-descriptions-item>
            <el-descriptions-item label="修改时间" :span="2">{{ current.updateTime }}</el-descriptions-item>
            <el-descriptions-item label="文件名" :span="2">{{ current.mapFileName }}</el-descriptions-item>
            <el-descriptions-item label="文件大小">{{ current.mapFileSize | fileSize }}</el-descriptions-item>
            <el-descriptions-item label="标签" :span="3" v-if="current.tags.length">
              <el-tag size="mini" type="info" v-for="tag in current.tags" :key="tag">{{ tag }}</el-tag>
            </el-descriptions-item>
            <el-descriptions-item label="可见性">
              <span v-if="current.visibility === 0">公开</span>
              <span v-if="current.visibility === 1">仅限好友</span>
              <span v-if="current.visibility === 2">私有</span>
              <span v-if="current.visibility === 3">非公开</span>
            </el-descriptions-item>
          </el-descriptions>
        </div>
        <el-button v-if="showMode === 'item'" round plain type="primary" @click="showUpdate">更新物品</el-button>
      </div>
    </el-drawer>
    <!-- endregion -->

    <!-- region 更新物品 -->
    <el-drawer :visible.sync="updateVisible" size="570px" direction="ltr">
      <el-form v-if="formData" :model="formData" ref="formUpdate" label-width="150px" style="padding: 10px;" label-position="left">
        <el-form-item label="标题" prop="title" required>
          <el-input v-model="formData.title"/>
        </el-form-item>
        <el-form-item label="描述" prop="description" required>
          <el-input v-model="formData.description" type="textarea" :rows="6" resize="none"/>
        </el-form-item>
        <el-form-item label="可见范围" prop="visibility" required>
          <el-select v-model="formData.visibility" style="width: 100%;">
            <el-option label="公开" :value="0"/>
            <el-option label="仅限好友" :value="1"/>
            <el-option label="私有" :value="2"/>
            <el-option label="非公开" :value="3"/>
          </el-select>
        </el-form-item>
        <el-form-item label="预览图" prop="previewFilePath" :required="publish || updatePreview">
          <el-tooltip :content="formData.previewFilePath" :disabled="!formData.previewFilePath || (!publish && !updatePreview)" placement="right-start">
            <el-image
              style="width: 100%; height: 200px;"
              fit="contain"
              :src="getAbsoluteUrl(formData.preview)"
              :preview-src-list="[getAbsoluteUrl(formData.preview)]"
            />
          </el-tooltip>
          <el-checkbox v-if="!publish" v-model="updatePreview">更新预览图</el-checkbox>
          &nbsp;&nbsp;
          <el-button :disabled="!publish && !updatePreview" size="mini" plain round type="primary" @click="choosePreviewFile">选择文件</el-button>
        </el-form-item>
        <el-form-item label="关卡文件" prop="mapFilePath" :required="publish || updateMap">
          <el-tooltip :content="formData.mapFilePath" :disabled="!formData.mapFilePath || (!publish && !updatePreview)" placement="right-start">
            <el-card style="width: 100%; height: 200px; margin-bottom: 5px;">
              <div style="display: flex; flex-direction: column; justify-content: space-between;">
                <template v-if="formData.mapFileName || formData.mapFileSize">
                  <h1>{{ formData.mapFileName }}</h1>
                  <h3>{{ formData.mapFileSize | fileSize }}</h3>
                </template>
              </div>
            </el-card>
          </el-tooltip>
          <el-checkbox v-if="!publish" v-model="updateMap">更新关卡文件</el-checkbox>
          &nbsp;&nbsp;
          <el-button
            :disabled="!publish && !updateMap"
            size="mini" plain round type="primary"
            @click="chooseMapFile"
          >选择文件</el-button>
          <el-button
            v-if="gameInfo && gameInfo.workshopType === 1"
            :disabled="!publish && !updateMap"
            size="mini" plain round type="primary"
            @click="chooseFolder"
          >选择文件夹</el-button>
        </el-form-item>
        <el-form-item label="标签" prop="tags">
          <div style="text-align: left; display: flex; flex-wrap: wrap;">
            <el-tag size="mini"  :closable="true" @close="removeTag(tag)" type="info" v-for="tag in formData.tags" style="margin: 5px;" :key="tag">{{ tag }}</el-tag>
            <el-tag size="mini" @click="addTag" style="cursor: pointer; margin: 5px;">添加</el-tag>
          </div>
        </el-form-item>
        <el-form-item label-width="0px">
          <el-button round plain type="primary" style="width: 100%;" @click="submit">提交</el-button>
        </el-form-item>
      </el-form>
    </el-drawer>
    <!--endregion -->

    <el-drawer :visible.sync="cloneVisible" size="570px" direction="ltr">
      <el-form v-if="formData" :model="formData" ref="formClone" label-width="150px" style="padding: 10px;" label-position="left">
        <el-form-item label="文件ID" prop="fileId" required>
          <el-input v-model="formData.fileId" readonly @change="changeFileId"/>
        </el-form-item>
        <el-form-item label="标题" prop="title" required>
          <el-input v-model="formData.title"/>
        </el-form-item>
        <el-form-item label="描述" prop="description" required>
          <el-input type="textarea" v-model="formData.description" :rows="6" resize="none"/>
        </el-form-item>
        <el-form-item label="可见范围" prop="visibility" required>
          <el-select v-model="formData.visibility" style="width: 100%;">
            <el-option label="公开" :value="0"/>
            <el-option label="仅限好友" :value="1"/>
            <el-option label="私有" :value="2"/>
            <el-option label="非公开" :value="3"/>
          </el-select>
        </el-form-item>
        <el-form-item label="预览图" prop="preview" required>
          <el-image
            style="width: 100%; height: 200px;"
            fit="contain"
            :src="getAbsoluteUrl(formData.preview)"
            :preview-src-list="[getAbsoluteUrl(formData.preview)]"
          />
        </el-form-item>
        <el-form-item label="关卡文件" prop="mapFileName" required>
          <el-card style="width: 100%; height: 200px; margin-bottom: 5px;">
            <div style="display: flex; flex-direction: column; justify-content: space-between;">
              <h1>{{ formData.mapFileName }}</h1>
              <h3>{{ formData.mapFileSize | fileSize }}</h3>
            </div>
          </el-card>
        </el-form-item>
        <el-form-item label="标签" prop="tags">
          <div style="text-align: left;">
            <el-tag size="mini" :closable="true" @close="removeTag(tag)" type="info" v-for="tag in formData.tags" style="margin: 5px;" :key="tag">{{ tag }}</el-tag>
            <el-tag size="mini" @click="addTag" style="cursor: pointer; margin: 5px;">添加</el-tag>
          </div>
        </el-form-item>
        <el-form-item label-width="0px">
          <el-button round plain type="primary" style="width: 100%;" @click="cloneMap">提交</el-button>
        </el-form-item>
      </el-form>
    </el-drawer>

    <el-drawer :visible.sync="queryVisible" size="570px" direction="ltr">
      <el-form :model="queryInfo" ref="formQuery" label-width="170px" style="padding: 10px;" label-position="left">
        <el-form-item label="查询方式" prop="queryWay" required>
          <el-select v-model="queryInfo.queryWay" style="width: 100%;">
            <el-option label="按作者" value="author"/>
            <el-option label="按物品" value="item"/>
          </el-select>
        </el-form-item>
        <el-form-item label="作者链接（或好友代码）" prop="authorUrl" v-if="queryInfo.queryWay === 'author'">
          <el-input
            type="text"
            v-model="queryInfo.authorUrl"
            placeholder="留空查询当前账号"
            @change="queryInfo.authorUrl && (queryInfo.authorType = 'published')"
          />
        </el-form-item>
        <el-form-item label="查询来源" prop="authorType" v-if="queryInfo.queryWay === 'author'" required>
          <el-select v-model="queryInfo.authorType" style="width: 100%;">
            <el-option :disabled="!!queryInfo.authorUrl" label="已订阅" value="subscribed"/>
            <el-option label="已发布" value="published"/>
            <el-option label="已收藏" value="favorited"/>
            <el-option :disabled="!!queryInfo.authorUrl" label="已评价" value="votedOn"/>
            <el-option :disabled="!!queryInfo.authorUrl" label="已好评" value="votedUp"/>
            <el-option :disabled="!!queryInfo.authorUrl" label="已差评" value="votedDown"/>
            <el-option label="已玩过" value="usedOrPlayed"/>
          </el-select>
        </el-form-item>
        <el-form-item label="物品链接" prop="itemUrl" v-if="queryInfo.queryWay === 'item'" required>
          <el-input type="textarea" v-model="queryInfo.itemUrl" :rows="6" resize="none"/>
        </el-form-item>
        <el-form-item label-width="0px">
          <el-button round plain type="primary" style="width: 100%;" @click="query">查询</el-button>
        </el-form-item>
      </el-form>
    </el-drawer>
  </div>
</template>

<script lang="ts">
/* eslint-disable @typescript-eslint/prefer-readonly */
import {Component, Ref, Watch} from 'vue-property-decorator';
import Toast from '@/components/common/Toast.vue';
import {registerEvents} from '@/utils/common_utils';
import BaseComponent from '@/components/common/BaseComponent';
import {
  getAbsoluteUrl,
  getPuzzleItems, getGameInfo,
  openMapFile, openPreviewFile, openFolder,
  execCommand, submit, cloneMap, showInWorkshop, showInLocalDirectory,
  init, queryWorkshopItem, query, operate,
  PuzzleItem, QueryInfo, GameInfo
} from '@/api/request/api';
import {MessageBoxInputData} from 'element-ui/types/message-box';
import {ElForm} from 'element-ui/types/form';

@Component({
  methods: {getAbsoluteUrl, showInWorkshop, showInLocalDirectory},
  components: {Toast}
})
export default class App extends BaseComponent {
  private readonly initPuzzleItems: Array<PuzzleItem> = [];

  private gameInfo: GameInfo = null;

  private puzzleItems = this.initPuzzleItems;

  private current: PuzzleItem = null;

  private formData: PuzzleItem = null;

  private updateMap = false;
  private updatePreview = false;
  private publish = false;
  private visible = false;
  private updateVisible = false;
  private cloneVisible = false;
  private queryVisible = false;
  private tagsVisible = false;
  private pageSize = 100;
  private currentPage = 1;
  private showMode = 'item';
  private queryInfo: QueryInfo = {
    queryWay: 'item',
    authorType: 'published',
    authorUrl: '',
    itemUrl: ''
  };

  private selectedItems: Array<PuzzleItem> = [];

  private selecting = false;

  @Ref('formUpdate')
  private formUpdate: ElForm;

  @Ref('formClone')
  private formClone: ElForm;

  @Ref('formQuery')
  private formQuery: ElForm;

  private get puzzleItemsPage() {
    const start = (this.currentPage - 1) * this.pageSize;
    const end = this.currentPage * this.pageSize;
    return this.puzzleItems.slice(start, end);
  }

  public override created() {
    registerEvents();
  }

  public override async mounted() {
    this.$toast.showLoading();
    await document.fonts.ready;
    this.gameInfo = await getGameInfo();
    console.log(this.gameInfo);
    this.puzzleItems = await getPuzzleItems();
    console.log(this.puzzleItems);
    await this.$sleep(500);
    this.$toast.close();
  }

  public override destroyed() {
    location.reload();
  }

  private showUpdate() {
    this.publish = this.updatePreview = this.updateMap = false;
    this.formData = {...this.current};
    this.updateVisible = true;
    this.formUpdate?.resetFields();
  }

  private async choosePreviewFile() {
    const previewFile = await openPreviewFile();
    if (previewFile) {
      this.$set(this.formData, 'preview', previewFile.url);
      this.$set(this.formData, 'previewFilePath', previewFile.path);
    }
  }

  private async chooseMapFile() {
    const mapFile = await openMapFile();
    if (mapFile) {
      this.$set(this.formData, 'mapFileName', mapFile.fileName);
      this.$set(this.formData, 'mapFileSize', mapFile.fileSize);
      this.$set(this.formData, 'mapFilePath', mapFile.path);
    }
  }

  private async chooseFolder() {
    const mapFile = await openFolder();
    if (mapFile) {
      this.$set(this.formData, 'mapFileName', mapFile.fileName);
      this.$set(this.formData, 'mapFileSize', mapFile.fileSize);
      this.$set(this.formData, 'mapFilePath', mapFile.path);
    }
  }

  private toggleTag(tag: string) {
    if (this.formData.tags.includes(tag)) {
      const index = this.formData.tags.indexOf(tag);
      this.formData.tags.splice(index, 1);
    } else {
      this.formData.tags.push(tag);
    }
  }

  private async execCommand(command: string) {
    await execCommand(command);
  }

  private async refresh() {
    this.$toast.showLoading();
    await init();
    this.puzzleItems = await getPuzzleItems();
    this.$toast.close();
  }

  private async submit() {
    try {
      await this.formUpdate.validate();
    } catch {
      return;
    }
    try {
      const commitData = {...this.formData};
      if (!this.publish && !this.updatePreview) {
        commitData.previewFilePath = null;
      }
      if (!this.publish && !this.updateMap) {
        commitData.mapFilePath = null;
      }
      this.$toast.showLoading();
      await submit(commitData);
      this.puzzleItems = await getPuzzleItems();
      this.updateVisible = false;
      this.$message.success('提交关卡完成');
    } finally {
      this.$toast.close();
    }
  }

  private newPuzzle() {
    this.publish = true;
    this.updatePreview = this.updateMap = false;
    this.formData = {
      fileId: 0,
      type: 2,
      previewFilePath: '',
      mapFilePath: '',
      preview: '',
      mapFileSize: 0,
      mapFileName: '',
      tags: []
    } as PuzzleItem;
    this.updateVisible = true;
    this.formUpdate?.resetFields();
  }

  private showClone() {
    this.formData = JSON.parse(JSON.stringify(this.current)) as PuzzleItem;
    this.cloneVisible = true;
    this.formClone?.resetFields();
  }

  private async query() {
    try {
      await this.formQuery.validate();
    } catch {
      return;
    }
    try {
      this.$toast.showLoading();
      this.puzzleItems = await query(this.queryInfo);
      this.queryVisible = false;
      this.showMode = 'query';
    } finally {
      this.$toast.close();
    }
  }

  private async cloneMap() {
    try {
      await this.formClone.validate();
    } catch {
      return;
    }
    try {
      const commitData = {...this.formData};
      this.$toast.showLoading();
      await cloneMap(commitData);
      this.puzzleItems = await getPuzzleItems();
      this.$message.success('克隆关卡完成');
      this.cloneVisible = false;
    } finally {
      this.$toast.close();
    }
  }

  private clickItem(item: PuzzleItem) {
    if (this.selecting) {
      if (item.fileId === 0) {
        return;
      }
      if (this.selectedItems.includes(item)) {
        const index = this.selectedItems.indexOf(item);
        this.selectedItems.splice(index, 1);
      } else {
        this.selectedItems.push(item);
      }
    } else {
      this.current = item;
      this.selectedItems.length = 0;
      this.selectedItems.push(this.current);
      this.visible = true;
    }
  }

  private async changeFileId() {
    this.formData = await queryWorkshopItem(this.formData.fileId);
  }

  private async operateBatch(type: string) {
    this.$toast.showProgress(0);
    let index = 0;
    const ids = this.selectedItems.length ? this.selectedItems.map(item => item.fileId) : [this.current.fileId];
    try {
      for (const id of ids) {
        await operate(id, type);
        this.$toast.showProgress(100 * ++index / ids.length);
      }
      await this.$sleep(500);
      this.$message({type: 'success', message: '操作成功'});
    } finally {
      this.$toast.close();
    }
  }

  private async copyItemUrls(...fileIds: Array<number>) {
    await this.$copyText(fileIds.map(id => 'https://steamcommunity.com/sharedfiles/filedetails/?id=' + id).join('\r\n'));
    this.$toast('复制成功');
  }

  @Watch('puzzleItems', {deep: false})
  private watchPuzzleItems() {
    this.visible = false;
  }

  private removeTag(tag: string) {
    this.formData.tags.splice(this.formData.tags.indexOf(tag), 1);
  }

  private async addTag() {
    const result = await this.$prompt('请输入要添加的标签', '添加标签') as MessageBoxInputData;
    const tag = result.value.trim();
    if (tag.length > 0 && !this.formData.tags.includes(tag)) {
      this.formData.tags.push(tag);
    }
  }
}
</script>
